package com.gitee.cui.netty.pipeline;

import com.gitee.cui.util.Logger;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.channel.embedded.EmbeddedChannel;
import org.junit.Test;

/**
 * Pipeline的出站处理流程演示类
 * @author cuiqingqiang
 * @version 1.0
 * @date 2021/10/22 8:36
 **/
public class OutPipeline {

    static class SimpleOutHandlerA extends ChannelOutboundHandlerAdapter {
        @Override
        public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
            Logger.info("出站处理器 A ：被调用");
            super.write(ctx, msg, promise);
        }
    }

    static class SimpleOutHandlerB extends ChannelOutboundHandlerAdapter {
        @Override
        public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
            Logger.info("出站处理器 B ：被调用");
            super.write(ctx, msg, promise);
        }
    }

    static class SimpleOutHandlerC extends ChannelOutboundHandlerAdapter {
        @Override
        public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
            Logger.info("出站处理器 C ：被调用");
            super.write(ctx, msg, promise);
        }
    }

    /**
     * [main|OutPipeline$SimpleOutHandlerC.write] |>  出站处理器 C ：被调用
     * [main|OutPipeline$SimpleOutHandlerB.write] |>  出站处理器 B ：被调用
     * [main|OutPipeline$SimpleOutHandlerA.write] |>  出站处理器 A ：被调用
     * 出站处理器的调用顺序与添加顺序刚好相反
     */
    @Test
    public void pipelineOutboundTest() {
        ChannelInitializer<EmbeddedChannel> channelInitializer = new ChannelInitializer<EmbeddedChannel>() {

            @Override
            protected void initChannel(EmbeddedChannel ch) throws Exception {
                ch.pipeline().addLast(new SimpleOutHandlerA());
                ch.pipeline().addLast(new SimpleOutHandlerB());
                ch.pipeline().addLast(new SimpleOutHandlerC());
            }
        };

        EmbeddedChannel embeddedChannel = new EmbeddedChannel(channelInitializer);
        ByteBuf buffer = Unpooled.buffer();
        buffer.writeInt(1);
        embeddedChannel.writeOutbound(buffer);
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static class SimpleOutHandlerB2 extends ChannelOutboundHandlerAdapter {
        @Override
        public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
            Logger.info("出站处理器 B2 ：被调用");
            // super.write(ctx, msg, promise);
        }
    }

    /**
     * [main|OutPipeline$SimpleOutHandlerC.write] |>  出站处理器 C ：被调用
     * [main|OutPipeline$SimpleOutHandlerB2.write] |>  出站处理器 B2 ：被调用
     * 后续的出站处理器A没有被调用，因为没有调用父类的super.write(ctx, msg, promise);方法，因此调用链被截断了
     */
    @Test
    public void pipelineOutboundCuttingTest() {
        ChannelInitializer<EmbeddedChannel> channelInitializer = new ChannelInitializer<EmbeddedChannel>() {

            @Override
            protected void initChannel(EmbeddedChannel ch) throws Exception {
                ch.pipeline().addLast(new SimpleOutHandlerA());
                ch.pipeline().addLast(new SimpleOutHandlerB2());
                ch.pipeline().addLast(new SimpleOutHandlerC());
            }
        };

        EmbeddedChannel embeddedChannel = new EmbeddedChannel(channelInitializer);
        ByteBuf buffer = Unpooled.buffer();
        buffer.writeInt(1);
        embeddedChannel.writeOutbound(buffer);
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
